#ifndef xpack_lang_cxx_parse_uri
#define xpack_lang_cxx_parse_uri
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"define/base_type.hpp"
#include"interface/can_alloc_seq.hpp"
#include"lang/cxx/private/lut.uri.hpp"
#include"lang/cxx/private/parse_xxx_result.hpp"
#include"lang/cxx/encode_first_as.hpp"
#include"lang/cxx.hpp"
#include"lang/wxx/length_if_as_utf8.hpp"
#include"lang/wxx/parse_hex.hpp"
#include"lang/wxx.hpp"
#include"macro/xexport.hpp"
#include"meta/remove_ref.hpp"
#include"meta/unsigned_type.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    template<class item_t>
    inline auto parse_uri_core(auto const & self, uri_t const & convert_free, auto const & alloc){
        using unsigned_t        = inc::unsigned_type<item_t>;
        using seq_t             = decltype(alloc(0));
        using result_t          = parse_uri_result<seq_t>;
        auto total_length       = uxx(0);
        auto i                  = uxx(0);
        auto len                = uxx(self->length);

        for(; i + 2 < len; total_length++, i++){
            if (auto c = unsigned_t(self[i]); c != '%'){ // 不是以 % 开头表示无需转换
                // 如果字符大于 128(通常是 unicode 字符)，或者是需要转换的 ascii 字符
                // 不符合要求，返回识别失败
                if (c >= 128 or convert_free[c] == false){
                    return result_t{}->index_of_error(i);
                }
                continue;
            }
            if (not inc::wxx<item_t>{ self[++i] }->is_hex or 
                not inc::wxx<item_t>{ self[++i] }->is_hex){
                return result_t{}->index_of_error(i);
            }
        }

        for(total_length += len - i; i < len; i++){
            if (auto c = unsigned_t(self[i]); c >= 128 or convert_free[c] == false){
                return result_t{}->index_of_error(i);
            }
        }

        auto buffer             = alloc(total_length);
        auto j                  = uxx(0);
        
        for(i = 0; i < len;){
            if (auto c = u08(self[i++]); c != '%'){
                buffer[j++]     = item_t(c);
                continue;
            }

            auto h              = u08(inc::w08{ char(self[i++]) }.parse_hex());
            auto l              = u08(inc::w08{ char(self[i++]) }.parse_hex());
            auto first          = char(h << 4 | l);

            if (sizeof(item_t) == 1 or u08(first) < 128){
                buffer[j++]     = item_t(first);
                continue;
            }

            char items[8]       = {};
            auto count          = inc::w08{ first }->length_if_as_utf8();
            auto need           = uxx(count - 1/*first*/) * 3;
            auto k              = uxx(1);
            auto i_old          = i;
            auto end            = i + need;

            for(items[0] = first; i + 3 <= end; i += 3){
                auto token      = char(self[i + 0]);
                auto wh         = char(self[i + 1]);
                auto wl         = char(self[i + 2]);

                if (token != '%'){
                    return result_t{}->index_of_error(i + 0);
                }
                if (not inc::w08{ wh }->is_hex){
                    return result_t{}->index_of_error(i + 1);
                }
                if (not inc::w08{ wl }->is_hex){
                    return result_t{}->index_of_error(i + 2);
                }

                auto h          = inc::w08{ wh }.parse_hex();
                auto l          = inc::w08{ wl }.parse_hex();
                items[k++]      = char(h << 4 | l);
            }

            if (auto item = inc::c08{ items, k }.encode_first_as<item_t>(); item->is_success){
                buffer[j++]     = item;
            }
            else{
                return result_t{}->index_of_error(i_old);
            }
        }
        return result_t { buffer };
    }

    template<class item_t>
    template<inc::can_alloc_seq alloc_seq_t>
    inline auto cxx<item_t>::parse_uri(alloc_seq_t const & alloc) const{
        auto allocx             = inc::can_alloc_seq_helper(alloc);
        return parse_uri_core<item_t>(xthe, make_uri, allocx);
    }
}

#endif
